/****************************************
 * @Date: 2021-08-11 16:41:12
 * @LastEditors: Alonc
 * @LastEditTime: 2022-09-02 14:50:57
 */

export class TimeUtil {
    /** 间隔天数 */
    public static daysBetween(time1: number | string | Date, time2: number | string | Date): number {
        if (time2 == undefined || time2 == null) {
            time2 = +new Date();
        }
        let startDate = new Date(time1).toLocaleDateString();
        let endDate = new Date(time2).toLocaleDateString();
        let startTime = new Date(startDate).getTime();
        let endTime = new Date(endDate).getTime();
        let dates = Math.abs((startTime - endTime)) / (1000 * 60 * 60 * 24);
        return dates;
    }

    /** 间隔秒数 */
    public static secsBetween(time1: number, time2: number) {
        if (time2 == undefined || time2 == null) {
            time2 = +new Date();
        }
        let dates = Math.abs((time2 - time1)) / (1000);
        return dates;
    }

    // 间隔时间 0d 0h 0m 0s
    public static between1(time1: number, time2: number) {
        let offset: number = time2 - time1;
        return this.formatTime1(offset);
    }

    /**
     * 代码休眠时间
     * @param ms 毫秒
     */
    public static async sleep(ms: number) {
        return new Promise<void>((resolve) => {
            setTimeout(() => {
                resolve();
            }, ms);
        });
    }

    // 返回时间格式: 0d 0h 0m 0s,为0的不显示
    public static formatTime1(time: number) {
        time = Math.floor(time / 1000);
        let d = Math.floor(time / 86400);
        let h = Math.floor((time % 86400) / 3600);
        let m = Math.floor((time % 3600) / 60);
        let s = time % 60;

        let str = "";
        if (d > 0) {
            str += `${ d }d `;
        }
        if (h > 0) {
            str += `${ h }h `;
        }
        if (m > 0) {
            str += `${ m }m `;
        }
        if (s > 0) {
            str += `${ s }s`;
        }
        return str;
    }

    // 返回时间格式: 00:00
    public static formatTime2(time: number) {
        time = Math.floor(time / 1000);
        let m = Math.floor((time % 3600) / 60);
        let s = time % 60;

        let str = "";
        if (m >= 10) {
            str += `${ m }`;
        } else {
            str += `0${ m }`;
        }
        str += ":";
        if (s >= 10) {
            str += `${ s }`;
        } else {
            str += `0${ s }`;
        }
        return str;
    }

    /**
     * 协调世界时 (UTC) 与 中国标准时间 (CST) 转换
     * @param timestamp 毫秒
     * @param type UTC / CST
     * @returns 
     */
    public static convertCSTAndUTC(timestamp: number, type: string): Date {
        const date = new Date(timestamp);
        const cstOffset = 8 * 60; // 中国标准时间比 UTC 早 8 小时
        const utcOffset = date.getTimezoneOffset(); // 当前时区的偏移量（分钟）
        let utcTimestamp = 0;
        if (type == "CST") {
            utcTimestamp = timestamp - (cstOffset + utcOffset) * 60 * 1000;
        } else {
            utcTimestamp = timestamp + (cstOffset + utcOffset) * 60 * 1000;
        }
        return new Date(utcTimestamp);
    }

    /**
     * string to timestamp
     * @param str 0:0:0
     * @returns timestamp
     */
    public static stringToTimestamp(time: string): number {
        const [hours, minutes, seconds] = time.split(':').map(Number);
        const now = new Date();
        now.setHours(hours, minutes, seconds, 0);
        return now.getTime();
    }

    public static getTimestampStage(time: number, list: number[]): number {
        let stage: number = -1;

        for (let i = 0; i < list.length; i++) {
            if (time < list[i]) {
                stage = i;
                break;
            }
        }

        return stage;
    }

    // 筛选离当前时间最近的时间
    public static getNearestTime(time: number, list: number[]): number {
        let nearestTime: number = 0;
        let nearestTimeDiff: number = Number.MAX_VALUE;

        for (let i = 0; i < list.length; i++) {
            let diff = Math.abs(time - list[i]);
            if (diff < nearestTimeDiff) {
                nearestTime = list[i];
                nearestTimeDiff = diff;
            }
        }

        return nearestTime;
    }

    public static getTimeStageInfo(time: number, refreshTimes: string[]): { stage: number, nextBuyTime: number; } {
        const timeList: number[] = refreshTimes.map((time) => {
            const t: number = TimeUtil.stringToTimestamp(time);
            return TimeUtil.convertCSTAndUTC(t, "CST").getTime();
        });

        let stage: number = TimeUtil.getTimestampStage(time, timeList);
        return { stage, nextBuyTime: timeList[stage] };
    }

    public static checkEverydayLimit(curTime: number, lastTimes: number[], refreshTimes: string[]): boolean {
        const nearestTime: number = Math.max(...lastTimes);
        const info: { stage: number, nextBuyTime: number; } = TimeUtil.getTimeStageInfo(nearestTime, refreshTimes);
        if (info.stage === -1) return true;  // 当天已经全部买完

        const nextBuyTime: number = info.nextBuyTime;
        return curTime < nextBuyTime;
    }
}